package com.hyts.mvc.servlet;

import com.hyts.bind.domain.BindDomains;
import com.hyts.bind.facade.BindContext;
import com.hyts.guava.array.Arrays;
import com.hyts.guava.object.Objects;
import com.hyts.mvc.annotation.MvcMapping;
import com.hyts.mvc.config.MvcValue;
import com.hyts.mvc.context.WebMvcContext;
import com.hyts.mvc.context.WebServletContextAware;
import com.hyts.mvc.handler.response.ResponseBodyProcessor;
import com.hyts.mvc.handler.response.ResponseHandler;
import com.hyts.mvc.handler.response.json.FastJsonResponseBodyProcessor;
import com.hyts.mvc.loader.WebMvcConfigLoader;
import com.hyts.mvc.model.HandlerWrapper;
import com.hyts.scanner.facade.ScannerBuilder;
import com.hyts.scanner.utility.StringUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

import static com.hyts.mvc.config.MvcValue.DEFAULT_VIEW_SERVLET_URL_PATH;

/**
 * project-name:coffice-toolbox
 * package-name:com.hyts.mvc.servlet
 * author:Libo/Alex
 * create-date:2019-06-16 18:12
 * copyright:libo-hyts-github
 * email:libo2dev@aliyun.com
 * description:此类主要用于: 主要用于总体mvc模式的转发功能实现servlet控制器
 */
@Slf4j
/*@WebServlet(name=MvcValueConfig.MVC_SERVLET_NAME,
            urlPatterns = MvcValueConfig.DEFAULT_VIEW_URL_PATH
            initParams = {@WebInitParam(name=)
 }
) */
public final class WebMvcServlet extends HttpServlet {

    /**
     * 初始化
     * @throws ServletException
     */
    @Override
    public void init() throws ServletException {
        log.info("开始初始化mvc核心控制器的组件和参数信息");
        //scanPackage
        String[] scanPackage = WebMvcContext.getMvcProperties().getScanPackage();
        WebMvcContext.setServletConfig(getServletConfig());
        WebMvcContext.setServletContext(getServletContext());
        //初始化handler操作容器
        WebMvcContext.initHandlerContainer();
        //初始化Guice的依赖注入服务
        WebMvcContext.setBindContext(new BindContext());
        WebMvcContext.setBindDomains(WebMvcContext.getBindContext().getBindDomains());
        WebMvcContext.getBindDomains().addBindSubject(ResponseHandler.class, FastJsonResponseBodyProcessor.class);
        List<Class<?>> classList = ScannerBuilder.create().
                annotation(MvcMapping.class).includePackage(scanPackage).scanToClass();
        classList.parallelStream().forEach(param->{
            WebMvcContext.getBindDomains().addBindSubject(param);
            MvcMapping mvcMapping = param.getAnnotation(MvcMapping.class);
            String classLevelPath = injectPathToken(StringUtils.isBlank(mvcMapping.value()[0])?
                    mvcMapping.path()[0]: mvcMapping.value()[0]);
            Method[] methods = param.getDeclaredMethods();
            for(Method method:methods){
                if(method.isAnnotationPresent(MvcMapping.class)){
                   MvcMapping mvcMapping1 =  method.getAnnotation(MvcMapping.class);
                   String methodLevelPath = null;
                   if(Objects.nonNull(mvcMapping1.path())  &&  mvcMapping1.path().length > 0){
                       methodLevelPath = classLevelPath+
                               injectPathToken(StringUtils.isBlank(mvcMapping1.value()[0])?
                                       mvcMapping1.path()[0]: mvcMapping1.value()[0]);
                   }else{
                       methodLevelPath = classLevelPath;
                   }
                   log.info("WebMVC-系统服务扫描控制器映射请求路径 : 【{}】 -> 对应的控制器Controller类:【{}】 -> 对应的全限定访问地址为:【{}】",methodLevelPath,param.getName());
                   WebMvcContext.getHandlerContainer().put(methodLevelPath,
                            HandlerWrapper.builder().clazz(param).executeMethod(method).bodyType(mvcMapping1.responseType()).build());
                }
            }
        });
    }

    /**
     * 操作服务开发实现-拦截所有请求
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<String> subfix = Arrays.toList(MvcValue.STATIC_SUBFIX_NAME).parallelStream().map(param->param.replace("\\*","")).collect(Collectors.toList());
        if(subfix.parallelStream().anyMatch(param->req.getServletPath().endsWith(param))){
            //req.getRequestDispatcher(req.getServletPath()).forward(req, resp);
            //resp.sendRedirect(req.getContextPath()+req.getServletPath());
 //           resp.getWriter().
            return ;
        }
        HandlerWrapper handlerWrapper = WebMvcContext.getHandlerContainer().get(req.getServletPath());
        try {
            if(Objects.isNull(handlerWrapper)){
                log.warn("path:{} is ignore",req.getServletPath());
                return ;
            }
            Object obj = WebMvcContext.getBindContext().getBean(handlerWrapper.getClazz());
            Method method = obj.getClass().getDeclaredMethod(handlerWrapper.getExecuteMethod().getName(),null);
            Object dataResult = method.invoke(obj,null);
            switch(handlerWrapper.getBodyType()){
                case REST:
                    ResponseHandler  responseHandler = WebMvcContext.getBindContext().getBean(ResponseHandler.class);
                    responseHandler.printer(req,resp,dataResult);
                    return ;
                case PAGE:

                default:
            }
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            log.error("mvc转发失败!",e);
        }
    }

    private static String injectPathToken(String path){
        if(path.startsWith("/")){
            return path;
        }else{
            return DEFAULT_VIEW_SERVLET_URL_PATH+path;
        }
    }

}
